package pers.bc.utils.net;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import pers.bc.utils.cons.PubConsUtilbc;
import pers.bc.utils.constant.IPubCons;
import pers.bc.utils.file.FileUtilbc;
import pers.bc.utils.file.StreamUtil;
import pers.bc.utils.pub.JudgeAssertUtil;
import pers.bc.utils.pub.LoggerUtil;
import pers.bc.utils.pub.PubEnvUtil;
import pers.bc.utils.pub.RandomUtil;
import pers.bc.utils.pub.StringUtil;
import pers.bc.utils.pub.XmlUtil;

public class HttpClient
{

    static String folder = "HttpClientULogs";
    static LoggerUtil logger = LoggerUtil.getInstance(folder);

    /**
     * *********************************************************** <br>
     * *说明： 上传 <br>
     * @see <br>
     * @param httpUrl
     * @param filePath
     *            @ * <br>
     * @void <br>
     * @methods pers.bc.utils.net.HttpFileUtil#uploadFile <br>
     * @author LiBencheng <br>
     * @date Created on 2024-10-29 <br>
     * @time 下午11:18:28 <br>
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    public static void uploadFile(String httpUrl, String filePath, Map<String, Object> params)
    {
        String boundary = Long.toHexString(System.currentTimeMillis()); // 随机边界
        HttpURLConnection connection = null;
        OutputStream output = null;
        PrintWriter writer = null;
        try
        {
            // 获取URLConnection对象对应的输出流
            connection = getHttpConnection(httpUrl);
            connection.setRequestProperty("Content-Type", "application/octet-stream");
            output = connection.getOutputStream();
            writer = new PrintWriter(new OutputStreamWriter(output, "UTF-8"), true);
            // 发送文件数据
            File file = new File(filePath);
            writer.append("--" + boundary).append(IPubCons.CRLF);
            writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"").append(IPubCons.CRLF);
            writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(file.getName())).append(IPubCons.CRLF);

            writer.append(IPubCons.CRLF).flush();
            // 发送请求参数
            writer.print(params);

            Files.copy(file.toPath(), output);

            writer.append(IPubCons.CRLF).flush(); // 结束行
            writer.append("--" + boundary + "--").append(IPubCons.CRLF);

            int responseCode = connection.getResponseCode();
            System.out.println("Response Code: " + responseCode);

        }
        catch (Throwable th)
        {
            JudgeAssertUtil.throwExceptionDir(th, folder);
        }
        finally
        {
            FileUtilbc.flush(output);
            FileUtilbc.close(output, writer);
            connection.disconnect();
        }

    }

    /**
     * *********************************************************** <br>
     * *说明：险下载，在上传 <br>
     * @see <br>
     * @param downUrl
     * @param saveDir
     * @param fileName
     * @param uploadUrl
     * @param params
     * @return <br>
     * @String <br>
     * @methods pers.bc.utils.net.HttpClientU#uploadFileNet <br>
     * @author LiBencheng <br>
     * @date Created on 2024-11-3 <br>
     * @time 下午1:34:21 <br>
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    public static String uploadFileNet(String downUrl, String saveDir, String fileName, String uploadUrl, Map<String, String> params)
    {
        InputStream downInStream = null;
        OutputStream uploadOutput = null;
        HttpURLConnection downConn = null;
        HttpURLConnection uploadConn = null;
        PrintWriter writer = null;
        String str = "";
        try
        {
            String boundary = Long.toHexString(System.currentTimeMillis()); // 随机边界
            downConn = getHttpConnection(downUrl);
            downInStream = downConn.getInputStream();
            Path target = Paths.get(saveDir, fileName);
            Files.createDirectories(target.getParent());
            Files.copy(downInStream, target, StandardCopyOption.REPLACE_EXISTING);
            File file = target.toFile();

            uploadConn = getHttpConnection(uploadUrl);
            uploadConn.setRequestMethod("POST");
            uploadOutput = uploadConn.getOutputStream();
            writer = new PrintWriter(new OutputStreamWriter(uploadOutput), true);

            // 发送文件数据
            // File file = new File(filePath);
            writer.append("--").append(boundary).append(IPubCons.CRLF);
            writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"").append(fileName).append("\"").append(IPubCons.CRLF);
            writer.append("Content-Type: ").append(URLConnection.guessContentTypeFromName(fileName)).append(IPubCons.CRLF);

            writer.append(IPubCons.CRLF).flush();
            // 发送请求参数
            writer.print(params);

            Files.copy(file.toPath(), uploadOutput);
            // 写入文件数据
            byte[] buffer = new byte[1024];
            int length = 0;
            while ((length = downInStream.read(buffer)) != -1)
            {
                uploadOutput.write(buffer, 0, length);
            }

            writer.append(IPubCons.CRLF).flush(); // 结束行
            writer.append("--").append(boundary).append("--").append(IPubCons.CRLF);
            str = StreamUtil.InputStreamTOString(uploadConn.getInputStream(), "utf-8");

            int responseCode = uploadConn.getResponseCode();
            System.out.println("Response Code: " + responseCode);

        }
        catch (Throwable th)
        {
            JudgeAssertUtil.throwExceptionDir(th, folder);
        }
        finally
        {
            FileUtilbc.close(downInStream, uploadOutput, writer);
            // assert downConn != null;
            // downConn.disconnect();
            // assert uploadConn != null;
            // uploadConn.disconnect();
        }

        return str;
    }

    /**
     * *********************************************************** <br>
     * *说明： 使用NIO下载文件<br>
     * @see <br>
     * @param httpUrl
     * @param saveDir
     * @param fileName
     * <br>
     * @void <br>
     * @methods pers.bc.utils.net.HttpFileUtil#downloadByNIO2 <br>
     * @author LiBencheng <br>
     * @date Created on 2024-10-29 <br>
     * @time 下午11:22:56 <br>
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    public static String downloadByNIO(String httpUrl, String saveDir, String fileName)
    {
        InputStream inStream = null;
        HttpURLConnection httpConn = null;
        try
        {
            httpConn = getHttpConnection(httpUrl);
            inStream = httpConn.getInputStream();
            fileName = PubEnvUtil.isEmpty(fileName) ? RandomUtil.number(20) : fileName;
            Path target = Paths.get(saveDir, fileName);
            Files.createDirectories(target.getParent());
            Files.copy(inStream, target, StandardCopyOption.REPLACE_EXISTING);

            return target.toFile().getPath();
        }
        catch (Throwable th)
        {
            JudgeAssertUtil.throwExceptionDir(th, folder);
        }
        finally
        {
            FileUtilbc.close(inStream);
        }

        return "";
    }

    public static String sendJsonPost(String url, String json)
    {
        OutputStream out = null;
        BufferedReader inputStreamReader = null;
        String result = "";
        try
        {
            // 打开URL连接
            HttpURLConnection httpConn = (HttpURLConnection) getHttpConnection(url);
            httpConn.setRequestMethod("POST"); // 设置请求方式
            httpConn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            httpConn.connect();
            if (!PubEnvUtil.isEmpty(json))
            {
                out = httpConn.getOutputStream();
                out.write(json.getBytes(PubConsUtilbc.UTF_8));
                out.flush();
            }
            // 获取响应
            result = StreamUtil.InputStreamTOString(httpConn.getInputStream(), StreamUtil.UTF_8);

            // inputStreamReader inputStreamReader = new BufferedReader(new
            // InputStreamReader(httpConn.getInputStream(), PubConsUtilbc.UTF_8));
            // // 读取响应
            // StringBuffer buffer = new StringBuffer();
            // String data = new String("");
            // while ((data = inputStreamReader.readLine()) != null)
            // {
            // buffer.append(data);
            // }
            // while ((data = inputStreamReader.readLine()) != null)
            // {
            // buffer.append(data);
            // }
        }
        catch (Exception e)
        {
            System.out.println("发送 sendJsonPost 请求出现异常！" + e);
            LoggerUtil.getInstance("httplogs").exception("jsonPost发送POST请求出现异常！", e);
        }
        finally
        {
            FileUtilbc.close(out, inputStreamReader);
        }

        return result;
    }

    public static Map<String, Object> sendWebXChange(String url, String xmlStr, Boolean isSaveXmlFile )
    {
        return sendWebXChange(url, xmlStr, isSaveXmlFile, Boolean.TRUE);
    }

    /**
     * *********************************************************** <br>
     * *说明：向交换平台发送数据 <br>
     * @see <br>
     * @param url
     * @param xmlStr
     * @param isSaveXmlFile
     * @return <br>
     * @Map<String,Object> <br>
     * @methods pers.bc.utils.net.HttpClient#sendWebXChange <br>
     * @author LiBencheng <br>
     * @date Created on 2024-11-16 <br>
     * @time 下午1:21:32 <br>
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> sendWebXChange(String url, String xmlStr, Boolean isSaveXmlFile, Boolean isCheck)
    {
        HttpURLConnection httpConn = null;
        Writer writer = null;
        InputStream inputStream = null;
        Map<String, Object> restmapMap = null;
        try
        {
            // 打开URL连接
            httpConn = (HttpURLConnection) getHttpConnection(url);
            httpConn.setRequestProperty("Content-Type", "application/xml");
            // 此种方式是按照UTF-8格式传输数据
            writer = new OutputStreamWriter(httpConn.getOutputStream(), IPubCons.UTF_8);
            writer.write(xmlStr);
            writer.flush();

            // 从连接的输入流中取得回执信息
            inputStream = httpConn.getInputStream();
            String restXml = StreamUtil.InputStreamTOString(inputStream, IPubCons.UTF_8);
            Map<String, Object> xmlToMap = XmlUtil.xmlToMap(StreamUtil.StringTOInputStream(restXml));
            if (isSaveXmlFile && PubEnvUtil.isNotNullObj(xmlToMap))
            {
                String filename = PubEnvUtil.EMPTY;
                if (PubEnvUtil.isNotNullObj((Map<String, Object>) xmlToMap.get("ufinterface"))
                        && PubEnvUtil.isNotNullObj(((Map<String, Object>) xmlToMap.get("ufinterface")).get("sendresult")))
                    filename =
                            StringUtil.valueOf(((Map<String, Object>) ((Map<String, Object>) xmlToMap.get("ufinterface")).get("sendresult"))
                                    .get("filename"));
                if (PubEnvUtil.isEmpty(filename)) filename = StringUtil.valueOf(System.currentTimeMillis());
                String saveDir = FileUtilbc.getWorkServerPath() + File.separator + "tempFile" + File.separator + "webXChange";
                Path target = Paths.get(saveDir, filename);
                Files.createDirectories(target.getParent());
                Files.copy(StreamUtil.StringTOInputStream(restXml), target, StandardCopyOption.REPLACE_EXISTING);

                // File file = new File(saveDir + System.currentTimeMillis() + ".xml");
                // if (!file.exists()) FileUtilbc.createFiles(saveDir);
                // FileUtilbc.write(file, restXml.replace(IPubCons.RN, IPubCons.EMPTY), IPubCons.UTF_8);
            }

            restmapMap = ((Map<String, Object>) ((Map<String, Object>) xmlToMap.get("ufinterface")).get("sendresult"));
            JudgeAssertUtil.checkAssert((isCheck && PubEnvUtil.unEquals(PubEnvUtil.ONE, restmapMap.get("resultcode"))),
                    StringUtil.valueOf(restmapMap.get("resultdescription")));

            restmapMap.put("restXml",restXml);

        }
        catch (Throwable e)
        {
            JudgeAssertUtil.throwException(e);
        }
        finally
        {
            FileUtilbc.close(inputStream,writer);
        }

        return restmapMap;
    }

    public String readDoc(org.w3c.dom.Document doc) throws Exception
    {
        String retString = "";
        try
        {
            javax.xml.transform.dom.DOMSource source = new javax.xml.transform.dom.DOMSource(doc);
            java.io.StringWriter writer = new java.io.StringWriter();
            javax.xml.transform.Result result = new javax.xml.transform.stream.StreamResult(writer);
            javax.xml.transform.Transformer transformer = javax.xml.transform.TransformerFactory.newInstance().newTransformer();
            transformer.transform(source, result);
            System.out.println(writer.getBuffer().toString());
            if (writer.getBuffer().toString().contains("<Result>1</Result>"))
            {
                retString = "Y";
            }
            else
            {
                retString = writer.getBuffer().toString();
            }
        }
        catch (Exception e)
        {
            JudgeAssertUtil.throwException(e);
        }
        return retString;
    }

    /**
     * *********************************************************** <br>
     * *说明： 发送POST请求<br>
     * @see <br>
     * @param url
     * @param parameters
     * @param contentType
     * @return <br>
     * @String <br>
     * @methods pers.bc.utils.net.HttpClient#sendPost <br>
     * @author LiBencheng <br>
     * @date Created on 2024-11-16 <br>
     * @time 下午12:02:56 <br>
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    public static String sendPost(String url, Map<String, String> parameters, String contentType)
    {
        String result = "";// 返回的结果
        BufferedReader in = null;// 读取响应输入流
        PrintWriter out = null;
        HttpURLConnection httpConn = null;

        try
        {
            // 打开URL连接
            httpConn = (HttpURLConnection) getHttpConnection(url);
            httpConn.setRequestProperty("Content-Type", contentType);
            if (PubEnvUtil.isNotEmptyObj(parameters.get("Access_token")))
                httpConn.setRequestProperty("Access_token", parameters.get("Access_token"));
            if (PubEnvUtil.isNotEmptyObj(parameters.get("Cookie"))) httpConn.setRequestProperty("Cookie", parameters.get("Cookie"));
            // 设置POST方式
            httpConn.setRequestMethod("POST");
            // 获取HttpURLConnection对象对应的输出流
            out = new PrintWriter(httpConn.getOutputStream());
            // 发送请求参数
            out.write(getPram(parameters));
            // flush输出流的缓冲
            out.flush();
            result = StreamUtil.InputStreamTOString(httpConn.getInputStream(), StreamUtil.UTF_8);

        }
        catch (Exception e)
        {
            System.out.println("发送 POST 请求出现异常！" + e);
            LoggerUtil.getInstance("httplogs").exception("sendPost发送POST请求出现异常！", e);
        }
        finally
        {
            // FileUtilbc.flush(out);
            FileUtilbc.close(out, in);
        }

        return result;
    }

    public static String sendGet(String url, Map<String, String> parameters)
    {
        String result = "";
        BufferedReader in = null;
        try
        {
            String urlNameString = url + "?" + getPram(parameters);
            // 打开和URL之间的连接
            HttpURLConnection connection = getHttpConnection(urlNameString);
            if (PubEnvUtil.isNotEmptyObj(parameters.get("Access_token")))
                connection.setRequestProperty("Access_token", parameters.get("Access_token"));
            if (PubEnvUtil.isNotEmptyObj(parameters.get("Cookie"))) connection.setRequestProperty("Cookie", parameters.get("Cookie"));
            // 设置POST方式
            connection.setRequestMethod("GET");
            // 建立实际的连接
            connection.connect();
            // 定义 BufferedReader输入流来读取URL的响应
            result = StreamUtil.InputStreamTOString(connection.getInputStream(), StreamUtil.UTF_8);

        }
        catch (Exception e)
        {
            System.out.println("【HTTP发送GET请求出现异常】:访问URL：" + url + ",错误：" + e.getMessage());
        }
        // 使用finally块来关闭输入流
        finally
        {
            try
            {
                if (in != null)
                    in.close();
            }
            catch (Exception e2)
            {
                System.out.println("【HTTP请求关闭输入流异常】:访问URL：" + url + ",错误：" + e2.getMessage());
                LoggerUtil.getInstance("httplogs").exception("【HTTP请求关闭输入流异常】:访问URL：" + url + ",错误：" + e2.getMessage(), e2);

            }
        }
        return result;
    }

    /**
     * *********************************************************** <br>
     * 说明：把request转换成json数据 <br>
     * @see <br>
     * @param request
     * @return <br>
     * @String <br>
     * @methods pers.bc.utils.net.HttpServletRequestUtil#readReqStr <br>
     * @author licheng <br>
     * @date Created on 2020年4月3日 <br>
     * @time 下午2:58:04 <br>
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    public static String readReqStr(@SuppressWarnings("restriction") HttpServletRequest request)
    {
        BufferedReader reader = null;
        StringBuilder sb = new StringBuilder();
        try
        {
            reader = new BufferedReader(new InputStreamReader(request.getInputStream(), "utf-8"));
            String line = null;

            while ((line = reader.readLine()) != null)
            {
                sb.append(line);
            }
        }
        catch (IOException th)
        {
            JudgeAssertUtil.throwExceptionDir(th, folder);
        }
        finally
        {
            FileUtilbc.close(reader);
        }

        return sb.toString();
    }

    /**
     * *********************************************************** <br>
     * 说明： <br>
     * @see <br>
     * @param request
     * @return <br>
     * @String <br>
     * @methods pers.bc.utils.net.HttpClientUtilbc#readReqXml <br>
     * @author LiBencheng <br>
     * @date Created on 2020-11-17 <br>
     * @time 下午6:39:23 <br>
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    public static String readReqXml(HttpServletRequest request)
    {
        String inputLine;
        String notityXml = "";
        BufferedReader reader = null;
        try
        {
            reader = request.getReader();
            while ((inputLine = request.getReader().readLine()) != null)
            {
                notityXml += inputLine;
            }
        }
        catch (IOException th)
        {
            JudgeAssertUtil.throwExceptionDir(th, folder);
        }
        finally
        {
            FileUtilbc.close(reader);
        }

        return notityXml;

    }

    /**
     * *********************************************************** <br>
     * *说明：把request转换成map数据 <br>
     * @see <br>
     * @param request
     * @return <br>
     * @Map<String,String> <br>
     * @methods pers.bc.utils.net.HttpClientUtilbc#getRequestParams <br>
     * @author LiBencheng <br>
     * @date Created on 2024-11-3 <br>
     * @time 下午12:58:56 <br>
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    public static Map<String, String> getRequestParams(HttpServletRequest request)
    {
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();)
        {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++)
            {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }

        logger.info("客户端信息："+ UserAgentUtil.getClientInfo(request));

        return params;
    }

    static String getPram(Map<String, String> parameters) throws UnsupportedEncodingException
    {

        StringBuffer sb = new StringBuffer();// 处理请求参数s
        String params = "";// 编码之后的参数
        // 编码请求参数
        if (parameters.size() == 1)
        {
            for (String name : parameters.keySet())
            {
                sb.append(name).append("=").append(URLEncoder.encode(parameters.get(name), PubConsUtilbc.UTF_8));
            }
            params = sb.toString();
        }
        else
        {
            for (String name : parameters.keySet())
            {
                sb.append(name).append("=").append(URLEncoder.encode(parameters.get(name), PubConsUtilbc.UTF_8)).append("&");
            }
            String temp_params = sb.toString();
            params = temp_params.substring(0, temp_params.length() - 1);
        }

        return params;
    }

    public static HttpURLConnection getHttpConnection(String httpUrl) throws MalformedURLException, IOException
    {
        // URLConnection conn = new URL(httpUrl).openConnection();
        HttpURLConnection conn = (HttpURLConnection) new URL(httpUrl).openConnection();
        // 设置通用的请求属性
        conn.setRequestProperty("Accept", "*/*");
        conn.setRequestProperty("Accept-Charset", PubConsUtilbc.UTF_8); // 设置接收数据的格式
        // application/octet-stream
        // application/x-www-form-urlencoded
        // application/xml
        // multipart/form-data
        // text/plain
        // application/octet-stream
        // application/x-msgpack
        // graphql
        conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
        conn.setRequestProperty("Connection", "keep-alive");
        conn.setRequestProperty("User-Agent",
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0");
        // 是建立连接的超时时间；
        conn.setConnectTimeout(30000);
        // 是传递数据的超时时间
        conn.setReadTimeout(500000);
        // 发送POST请求必须设置如下两行
        conn.setDoOutput(true);
        conn.setDoInput(true);
        // conn.setRequestMethod("POST");

        return conn;
    }
}
